package java8.stream;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamDemo {
    private static void demo1(){
        List<String> list = Arrays.asList("aaaa", "bbbb", "cccc", "aaa3", "aaa2", "ddd");

        list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);

        System.out.println("-------------");

        list.stream().sorted().forEach(System.out::println);

        System.out.println("-------------");

        list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

        System.out.println("-------------");

        //aaa2#aaa3#aaaa#bbbb#cccc#ddd
        System.out.println(list.stream().sorted().reduce((a, b) -> a + "#" + b).get());

        System.out.println("-------------");

        System.out.println(list.stream().filter(s -> s.startsWith("b")).count());

        System.out.println("-------------");

        System.out.println(list.stream().noneMatch(s -> s.startsWith("b")));
        System.out.println("-------------");

        System.out.println(list.stream().allMatch(s -> s.startsWith("a")));

        System.out.println("-------------");
        System.out.println(list.stream().anyMatch(s -> s.startsWith("a")));
    }

    public static final int MAX = 1000000;

    private static void sortDemo1(){
        List<String> values = new ArrayList<>(MAX);

        for (int i = 0; i < MAX; i++) {
            UUID uuid = UUID.randomUUID();
            values.add(uuid.toString());
        }


        long start = System.nanoTime();

        long count = values.stream().sorted().count();
        System.out.println(count);

        long end = System.nanoTime();

        long millis = TimeUnit.NANOSECONDS.toMillis(end - start);

        System.out.println(String.format("sort1: %d ms", millis));
    }

    private static void sortDemo2(){
        List<String> values = new ArrayList<>(MAX);

        for (int i = 0; i < MAX; i++) {
            UUID uuid = UUID.randomUUID();
            values.add(uuid.toString());
        }


        long start = System.nanoTime();

//        parallelStream是一个并行执行的流，其使用 fork/join （ForkJoinPool）并行方式来拆分任务和加速处理过程。研究parallelStream之前，搞清楚ForkJoinPool是很有必要的。
//        ForkJoinPool的核心是采用分治法的思想，将一个大任务拆分为若干互不依赖的子任务，把这些子任务分别放到不同的队列里，并为每个队列创建一个单独的线程来执行队列里的任务。同时，为了最大限度地提高并行处理能力，采用了工作窃取算法来运行任务，也就是说当某个线程处理完自己工作队列中的任务后，尝试当其他线程的工作队列中窃取一个任务来执行，直到所有任务处理完毕。所以为了减少线程之间的竞争，通常会使用双端队列，被窃取任务线程永远从双端队列的头部拿任务执行，而窃取任务的线程永远从双端队列的尾部拿任务执行。
        //用parallStream这是一个并发操作，你必须要使用线程安全的集合才可以
        long count = values.parallelStream().sorted().count();
        System.out.println(count);

        long end = System.nanoTime();

        long millis = TimeUnit.NANOSECONDS.toMillis(end - start);

        System.out.println(String.format("sort2: %d ms", millis));
    }


    private static void parallelStreamDemo(){
        List<String> list = new ArrayList<>();

        IntStream.range(0, 1000).forEach(i -> list.add("str" + i));

        //java.lang.ArrayIndexOutOfBoundsException
//        List<String> copyList = new ArrayList<>();

        List<String> copyList = new CopyOnWriteArrayList<>();

        list.parallelStream().forEach(i -> {
            copyList.add(i);
        });

        System.out.println(copyList.size());

    }

    private static void intStreamDemo(){
        //45
        OptionalInt reduce = IntStream.range(0, 10).reduce((a, b) -> a + b);

        System.out.println(reduce.getAsInt());

        //52=7+45
        int reduce1 = IntStream.range(0, 10).reduce(7, (a, b) -> a + b);

        System.out.println(reduce1);

    }

    private static void averageDemo(){
        Stream.of(new BigDecimal("1.25"), new BigDecimal("3.7"), new BigDecimal("6.5"))
                .mapToDouble(BigDecimal::doubleValue)
                .average()
                .ifPresent(System.out::println);
    }

    public static void main(String[] args) {
//        demo1();

//        //sort1: 1599 ms
//        sortDemo1();
//        //sort2: 632 ms
//        sortDemo2();

//        parallelStreamDemo();
//        intStreamDemo();
        averageDemo();
    }
}
